/******************************************************************
 * Copyright (c) 2025 Bocloud Technologies Co., Ltd.
 * installer is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain n copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 ******************************************************************/

package utils

import (
	"net"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/sunvim/dogesyncer/helper"
)

func Exists(path string) bool {
	_, err := os.Stat(path)
	if err != nil {
		return os.IsExist(err)
	}
	return true
}

func ContainsString(slice []string, s string) bool {
	for _, item := range slice {
		if item == s {
			return true
		}
	}
	return false
}

func ContainsStringPrefix(slice []string, s string) bool {
	for _, item := range slice {
		if strings.HasPrefix(item, s) {
			return true
		}
	}
	return false
}

// IsDir 判断所给路径是否为文件夹
func IsDir(path string) bool {
	s, err := os.Stat(path)
	if err != nil {
		return false
	}
	return s.IsDir()
}

// IsFile 判断所给路径是否为文件
func IsFile(path string) bool {
	s, err := os.Stat(path)
	if err != nil {
		return false
	}
	return !s.IsDir()
}

func AbsPath(path string) (string, error) {
	if filepath.IsAbs(path) {
		return path, nil
	} else {
		return filepath.Abs(path)
	}
}

func DirectoryIsEmpty(path string) bool {
	dir, _ := os.ReadDir(path)
	if len(dir) == 0 {
		return true
	}
	return false
}

func GetOutBoundIP() (ip string, err error) {
	conn, err := net.Dial("udp", "8.8.8.8:53")
	if err != nil {
		return
	}
	localAddr := conn.LocalAddr().(*net.UDPAddr)
	ip = strings.Split(localAddr.String(), ":")[0]
	return
}

func GetIntranetIp() (ip string, err error) {
	addresses, err := net.InterfaceAddrs()
	if err != nil {
		return
	}
	for _, address := range addresses {
		if ipNet, ok := address.(*net.IPNet); ok && !ipNet.IP.IsLoopback() {
			if ipNet.IP.To4() != nil {
				return ipNet.IP.String(), nil
			}
		}
	}
	return
}

func IsNum(s string) bool {
	_, err := strconv.ParseFloat(s, 64)
	return err == nil
}

//var letterRunes = []rune("abcdefghijklmnopqrstuvwxyz123456789")
//
//func RandStringRunes(n int) string {
//	b := make([]rune, n)
//	for i := range b {
//		b[i] = letterRunes[rand.Intn(len(letterRunes))]
//	}
//	return string(b)
//}

func CopyFile(sourceFile, destinationFile string) error {
	input, err := os.ReadFile(sourceFile)
	if err != nil {
		return err
	}
	err = os.WriteFile(destinationFile, input, 0644)
	if err != nil {
		return err
	}
	return nil
}

func RemoveStringObject(array []string, obj string) []string {
	for i := 0; i < len(array); i++ {
		if array[i] == obj {
			array = append(array[:i], array[i+1:]...)
		}
	}
	return array
}

func IsChanClosed(ch interface{}) bool {
	return helper.IsChanClosed(ch)
}

// ReverseArray reverse array
func ReverseArray(arr []string) []string {
	for i, j := 0, len(arr)-1; i < j; i, j = i+1, j-1 {
		arr[i], arr[j] = arr[j], arr[i]
	}
	return arr
}

// CopyMap copy map
func CopyMap(originalMap map[string]string) map[string]string {
	copiedMap := make(map[string]string)
	for key, value := range originalMap {
		copiedMap[key] = value
	}
	return copiedMap
}

func CopyDir(src, dst string) error {
	return filepath.Walk(src, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		dstPath := filepath.Join(dst, path[len(src):])
		if info.IsDir() {
			if !Exists(dstPath) {
				err = os.MkdirAll(dstPath, info.Mode())
				if err != nil {
					return err
				}
			}
		} else {
			if !Exists(dstPath) {
				err = CopyFile(path, dstPath)
				if err != nil {
					return err
				}
			}
		}
		return nil
	})
}

func LoopIP(domain string) ([]string, error) {
	ip4 := []string{}
	ips, err := net.LookupIP(domain)
	if err != nil {
		return ip4, err
	}
	for _, ip := range ips {
		if ip.To4() != nil {
			ip4 = append(ip4, ip.To4().String())
		}
	}
	return ip4, err
}
